Skip to content

feat: extend 4 REST endpoints + migrate 7 DDP callers#40711

Merged
ggazzo merged 16 commits into
developfrom
chore/ddp-migrate-batch2
Jun 15, 2026
Merged

feat: extend 4 REST endpoints + migrate 7 DDP callers#40711
ggazzo merged 16 commits into
developfrom
chore/ddp-migrate-batch2

Conversation

@ggazzo

@ggazzo ggazzo commented May 27, 2026

Copy link
Copy Markdown
Member

Summary

Second batch of the DDP→REST caller migration. Adds three small REST endpoint extensions (so the client can stop hitting DDP for these flows) and swaps six client call-sites over to REST. Each DDP method stays registered on the server with a deprecation log pointing at the REST route — external SDK / mobile clients keep working until the 9.0.0 sweep removes them.

The subscriptions.read tmid extension and its thread read-marker callers (ThreadChat.tsx, useThreadMessagesQuery.ts) were split out into #40957.

REST endpoint changes

Endpoint Change
POST /v1/chat.delete Body now accepts { fileId, asUser? } as an alternative to { msgId, roomId, asUser? }. When fileId is supplied the server resolves the owning message via Messages.getMessageByFileId.
POST /v1/users.setPreferences data.utcOffset (number) is now accepted. Server writes to the user-document root via Users.setUtcOffset (not the settings.preferences subdoc), matching the legacy DDP behavior.
GET /v1/spotlight Now accepts usernames (CSV), type (JSON-encoded { users?, mentions?, rooms?, includeFederatedRooms? }) and rid. Response items expose nickname/outside/uids/usernames/fname that DDP already returned. status on user items is optional (outside/federated users never had one). authRequired flipped to false to keep Accounts_AllowAnonymousRead flows working.

Caller migrations

DDP REST Caller(s)
loadMissedMessages GET /v1/chat.syncMessages useLoadMissedMessages.ts (maps each result through mapMessageFromApi)
joinRoom POST /v1/channels.join hooks/useJoinRoom.ts, lib/chats/data.ts (channel-only; non-c rooms error via REST same as DDP)
userSetUtcOffset POST /v1/users.setPreferences client/startup/startup.ts (2 sites)
deleteFileMessage POST /v1/chat.delete useDeleteFile.tsx
spotlight GET /v1/spotlight useSearchItems.ts, ComposerPopupProvider.tsx
listCustomSounds GET /v1/custom-sounds.list CustomSoundProvider.tsx

A TODO(ddp-removal) comment on useJoinRoom and data.ts flags the spot where we'd want a type-agnostic /v1/rooms.join later.

Test plan

  • Disconnect/reconnect with an open channel → missed messages load.
  • Open a non-subscribed public channel → join button works.
  • Login from a new device on a different timezone → user.utcOffset updates.
  • Delete a file message from the Files tab.
  • Search a username/channel from the navbar.
  • Mention @user / #room from the composer.
  • Anonymous-mode workspace (Accounts_AllowAnonymousRead) → navbar search resolves general.
  • Sound preferences pick up workspace custom sounds.

Task: ARCH-2164

@ggazzo ggazzo requested review from a team as code owners May 27, 2026 15:47
@dionisio-bot

dionisio-bot Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented May 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e26ed03

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@rocket.chat/meteor Minor
@rocket.chat/rest-typings Minor
@rocket.chat/core-typings Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ggazzo ggazzo marked this pull request as draft May 27, 2026 15:48
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR migrates several client DDP callers to REST endpoints, extends REST contracts (chat.delete supports fileId; spotlight accepts usernames/type/rid and allows anonymous access; subscriptions.read accepts tmid to mark a thread read; users.setPreferences accepts data.utcOffset), adds readThreadMethod, logs deprecation for legacy DDP methods, and adds E2E tests and changesets.

Changes

DDP to REST Migration & Endpoint Enhancements

Layer / File(s) Summary
REST endpoint contract updates
packages/rest-typings/src/v1/chat.ts, packages/rest-typings/src/v1/misc.ts, packages/rest-typings/src/v1/subscriptionsEndpoints.ts, packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts
ChatDelete now supports { msgId, roomId } or { fileId }; Spotlight request adds optional usernames, type, rid and response users/rooms fields are relaxed; SubscriptionsRead adds optional tmid; UsersSetPreferencesParamsPOST adds optional data.utcOffset.
Server API handlers
apps/meteor/app/api/server/v1/chat.ts, apps/meteor/app/api/server/v1/misc.ts, apps/meteor/app/api/server/v1/subscriptions.ts
/v1/chat.delete resolves messages by fileId or msgId and cleans up uploads when message missing; /v1/spotlight accepts anonymous calls and parses usernames/type/rid; /v1/subscriptions.read supports tmid to mark a single thread read via readThreadMethod.
Server method deprecations & preferences
apps/meteor/server/methods/*, apps/meteor/app/lib/server/methods/joinRoom.ts, apps/meteor/app/custom-sounds/server/methods/listCustomSounds.ts, apps/meteor/server/publications/spotlight.ts
Legacy DDP methods now log deprecation entries referencing REST routes; saveUserPreferences accepts utcOffset and persists it via Users.setUtcOffset.
Thread helper and delegation
apps/meteor/app/threads/server/functions.ts, apps/meteor/server/methods/readThreads.ts
Added exported readThreadMethod that enforces threads gating, access checks, callbacks, and delegates to readThread; readThreads Meteor method now delegates to readThreadMethod and logs deprecation.
Client hook and component REST migrations
apps/meteor/client/hooks/useJoinRoom.ts, apps/meteor/client/lib/chats/data.ts, apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts, apps/meteor/client/startup/startup.ts, apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useDeleteFile.tsx, apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx, apps/meteor/client/views/room/contextualBar/Threads/*, apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts, apps/meteor/client/providers/CustomSoundProvider/*
Multiple client-side callers switched from useMethod/sdk.call to useEndpoint or sdk.rest: join → /v1/channels.join, delete-file → /v1/chat.delete with fileId, spotlight → /v1/spotlight with object params, subscriptions.read → /v1/subscriptions.read with tmid, loadMissedMessages → /v1/chat.syncMessages, custom sounds list → /v1/custom-sounds.list, UTC offset persisted via /v1/users.setPreferences.
End-to-end tests
apps/meteor/tests/end-to-end/api/*
Added E2E tests for chat.delete by fileId, spotlight params and anonymous access, subscriptions.read tmid success/failure, and users.setPreferences utcOffset validation/persistence.
Changeset documentation
.changeset/*
Release notes documenting the DDP→REST migration, deprecation logging, and the specific REST contract changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • RocketChat/Rocket.Chat#40677: Adjusts deprecation-logger/CI behavior that interacts with the deprecation logging and API tests introduced here.

Suggested reviewers

  • tassoevan
  • sampaiodiego
  • ricardogarim
  • gabriellsh
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: extending 4 REST endpoints and migrating 7 DDP callers to use those endpoints instead of DDP methods.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 17 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/meteor/_build/main-prod/server-rspack.js Outdated
Comment thread apps/meteor/_build/main-prod/client-rspack.js Outdated
@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 57.77778% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.18%. Comparing base (57c4cb7) to head (e26ed03).
⚠️ Report is 12 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #40711      +/-   ##
===========================================
+ Coverage    70.05%   70.18%   +0.12%     
===========================================
  Files         3355     3355              
  Lines       129162   129266     +104     
  Branches     22333    22329       -4     
===========================================
+ Hits         90487    90722     +235     
+ Misses       35387    35254     -133     
- Partials      3288     3290       +2     
Flag Coverage Δ
e2e 59.25% <59.37%> (-0.11%) ⬇️
e2e-api 47.07% <57.14%> (+0.81%) ⬆️
unit 70.14% <33.33%> (+0.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ggazzo ggazzo added this to the 8.6.0 milestone May 28, 2026
@ggazzo ggazzo marked this pull request as ready for review May 28, 2026 16:48
@ggazzo ggazzo requested a review from a team as a code owner May 28, 2026 16:48
@ggazzo

ggazzo commented May 28, 2026

Copy link
Copy Markdown
Member Author

/jira ARCH-2156

@hacktron-app hacktron-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Severity Count
🟡 Medium 1

View full scan results

Comment on lines +549 to +559
const msg =
'fileId' in this.bodyParams
? await Messages.getMessageByFileId(this.bodyParams.fileId)
: await Messages.findOneById(this.bodyParams.msgId, { projection: { u: 1, rid: 1 } });

if (!msg) {
return API.v1.failure(`No message found with the id of "${this.bodyParams.msgId}".`);
const ref = 'fileId' in this.bodyParams ? `the file id of "${this.bodyParams.fileId}"` : `the id of "${this.bodyParams.msgId}"`;
return API.v1.failure(`No message found with ${ref}.`);
}

if (this.bodyParams.roomId !== msg.rid) {
if ('roomId' in this.bodyParams && this.bodyParams.roomId !== msg.rid) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium: Missing Authorization Check in chat.starMessage/unStarMessage

The chat.starMessage and chat.unStarMessage endpoints allow a user to star or unstar any message by providing its messageId. The implementation retrieves the message from the database and passes it to the starMessage function without verifying if the authenticated user has access to the room where the message resides. An attacker could potentially star/unstar messages in rooms they are not authorized to access.

Trace
graph TD
    subgraph SG0 ["apps/meteor/app/2fa/server/code/index.ts"]
        checkCodeForUser["checkCodeForUser"]
    end
    style SG0 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG1 ["apps/meteor/app/api/server/ApiClass.ts"]
        generateConnection["Generates a connection object for API requests."]
        APIClass.shouldAddRateLimitToRoute["APIClass.shouldAddRateLimitToRoute"]
        APIClass.success["Formats a successful API response."]
        APIClass.failure["APIClass.failure"]
        APIClass.internalError["Formats an internal server error API response."]
        APIClass.unauthorized["Formats an unauthorized API response."]
        APIClass.forbidden["APIClass.forbidden"]
        APIClass.tooManyRequests["APIClass.tooManyRequests"]
        APIClass.shouldVerifyRateLimit["APIClass.shouldVerifyRateLimit"]
        APIClass.enforceRateLimit["APIClass.enforceRateLimit"]
        APIClass.addRateLimiterRuleForRoutes["APIClass.addRateLimiterRuleForRoutes"]
        APIClass.processTwoFactor["APIClass.processTwoFactor"]
        APIClass.getFullRouteName["APIClass.getFullRouteName"]
        APIClass.namedRoutes["APIClass.namedRoutes"]
        APIClass.registerTypedRoutesLegacy["APIClass.registerTypedRoutesLegacy"]
        APIClass.registerTypedRoutes["APIClass.registerTypedRoutes"]
        APIClass.method["Internal helper to register an API method."]
        APIClass.get["Registers a GET API route."]
        APIClass.post["Registers a POST API route."]
        APIClass.addRoute["APIClass.addRoute"]
        APIClass.this.parseJsonQuery["APIClass.this.parseJsonQuery"]
        APIClass.authenticatedRoute["APIClass.authenticatedRoute"]
        APIClass.loginCompatibility["Adapts login credentials for compatibility."]
        APIClass.createMeteorInvocation["APIClass.createMeteorInvocation"]
        APIClass.applyInvocation["APIClass.applyInvocation"]
    end
    style SG1 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG2 ["apps/meteor/app/api/server/api.helpers.ts"]
        isLegacyPermissionsPayload["isLegacyPermissionsPayload"]
        isLightPermissionsPayload["isLightPermissionsPayload"]
        isPermissionsPayload["isPermissionsPayload"]
        checkPermissionsForInvocation["checkPermissionsForInvocation"]
        checkPermissions["checkPermissions"]
        parseDeprecation["parseDeprecation"]
    end
    style SG2 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG3 ["apps/meteor/app/api/server/helpers/getUserInfo.ts"]
        isVerifiedEmail["isVerifiedEmail"]
        getUserPreferences["getUserPreferences"]
        filterOutdatedVersionUpdateBanners["filterOutdatedVersionUpdateBanners"]
        getUserCalendar["getUserCalendar"]
        getUserInfo["Constructs user information object for API responses."]
    end
    style SG3 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG4 ["apps/meteor/app/api/server/middlewares/authenticationHono.ts"]
        isUserWithUsername["isUserWithUsername"]
        authenticationMiddlewareForHono["authenticationMiddlewareForHono"]
    end
    style SG4 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG5 ["apps/meteor/app/api/server/middlewares/permissions.ts"]
        permissionsMiddleware["permissionsMiddleware"]
    end
    style SG5 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG6 ["apps/meteor/app/api/server/router.ts"]
        convertHonoContextToApiActionContext["convertHonoContextToApiActionContext"]
    end
    style SG6 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG7 ["apps/meteor/app/api/server/v1/chat.ts"]
        ._Rocket.Chat_apps_meteor_app_api_server_v1_chat.ts{{"Registers and implements REST API endpoints for chat operations such as pinning, updating, starring, following messages, reacting, reporting, deleting, searching, and managing threads."}}
    end
    style SG7 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG8 ["apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts"]
        endpoint["endpoint"]
    end
    style SG8 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG9 ["apps/meteor/app/utils/lib/getURL.ts"]
        getURL_2["_getURL"]
        getURLWithoutSettings["getURLWithoutSettings"]
    end
    style SG9 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG10 ["apps/meteor/app/utils/server/functions/getBaseUserFields.ts"]
        getBaseUserFields["getBaseUserFields"]
    end
    style SG10 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG11 ["apps/meteor/app/utils/server/functions/getDefaultUserFields.ts"]
        getDefaultUserFields["Returns the default database fields allowed for user objects."]
    end
    style SG11 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG12 ["apps/meteor/app/utils/server/getURL.ts"]
        getURL["getURL"]
    end
    style SG12 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG13 ["apps/meteor/app/utils/server/lib/getUserPreference.ts"]
        getUserPreference["getUserPreference"]
    end
    style SG13 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG14 ["apps/meteor/ee/app/api-enterprise/server/middlewares/license.ts"]
        license["license"]
    end
    style SG14 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG15 ["apps/meteor/lib/utils/isObject.ts"]
        isObject["isObject"]
    end
    style SG15 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG16 ["apps/meteor/server/lib/shouldBreakInVersion.ts"]
        shouldBreakInVersion["shouldBreakInVersion"]
    end
    style SG16 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG17 ["ee/apps/account-service/src/lib/utils.ts"]
        hashLoginToken["_hashLoginToken"]
    end
    style SG17 fill:#2a2a2a,stroke:#444,color:#aaa
    subgraph SG18 ["packages/logger/src/index.ts"]
        Logger.error["Logger.error"]
    end
    style SG18 fill:#2a2a2a,stroke:#444,color:#aaa
    ._Rocket.Chat_apps_meteor_app_api_server_v1_chat.ts --> APIClass.get
    ._Rocket.Chat_apps_meteor_app_api_server_v1_chat.ts --> APIClass.post
    APIClass.get --> APIClass.method
    APIClass.post --> getUserInfo
    APIClass.post --> generateConnection
    APIClass.post --> APIClass.success
    APIClass.post --> APIClass.internalError
    APIClass.post --> APIClass.unauthorized
    APIClass.post --> APIClass.method
    APIClass.post --> APIClass.loginCompatibility
    APIClass.post --> getDefaultUserFields
    APIClass.method --> APIClass.registerTypedRoutes
    APIClass.method --> APIClass.addRoute
    getUserInfo --> isVerifiedEmail
    getUserInfo --> getUserPreferences
    getUserInfo --> filterOutdatedVersionUpdateBanners
    getUserInfo --> getUserCalendar
    getUserInfo --> getURL
    APIClass.success --> isObject
    APIClass.loginCompatibility --> APIClass.get
    getDefaultUserFields --> getBaseUserFields
    APIClass.addRoute --> hashLoginToken
    APIClass.addRoute --> shouldBreakInVersion
    APIClass.addRoute --> generateConnection
    APIClass.addRoute --> APIClass.shouldAddRateLimitToRoute
    APIClass.addRoute --> APIClass.failure
    APIClass.addRoute --> APIClass.unauthorized
    APIClass.addRoute --> APIClass.forbidden
    APIClass.addRoute --> APIClass.tooManyRequests
    APIClass.addRoute --> APIClass.enforceRateLimit
    APIClass.addRoute --> APIClass.addRateLimiterRuleForRoutes
    APIClass.addRoute --> APIClass.processTwoFactor
    APIClass.addRoute --> APIClass.getFullRouteName
    APIClass.addRoute --> APIClass.registerTypedRoutesLegacy
    APIClass.addRoute --> APIClass.get
    APIClass.addRoute --> APIClass.this.parseJsonQuery
    APIClass.addRoute --> APIClass.createMeteorInvocation
    APIClass.addRoute --> APIClass.applyInvocation
    APIClass.addRoute --> authenticationMiddlewareForHono
    APIClass.addRoute --> permissionsMiddleware
    APIClass.addRoute --> checkPermissions
    APIClass.addRoute --> parseDeprecation
    APIClass.addRoute --> license
    getUserPreferences --> getUserPreference
    getURL --> getURLWithoutSettings
    APIClass.failure --> isObject
    APIClass.enforceRateLimit --> APIClass.shouldVerifyRateLimit
    APIClass.addRateLimiterRuleForRoutes --> APIClass.namedRoutes
    APIClass.processTwoFactor --> APIClass.get
    APIClass.processTwoFactor --> checkCodeForUser
    APIClass.registerTypedRoutesLegacy --> APIClass.registerTypedRoutes
    APIClass.this.parseJsonQuery --> APIClass.this.parseJsonQuery
    authenticationMiddlewareForHono --> APIClass.unauthorized
    authenticationMiddlewareForHono --> APIClass.get
    authenticationMiddlewareForHono --> APIClass.authenticatedRoute
    authenticationMiddlewareForHono --> convertHonoContextToApiActionContext
    authenticationMiddlewareForHono --> isUserWithUsername
    permissionsMiddleware --> APIClass.internalError
    permissionsMiddleware --> APIClass.unauthorized
    permissionsMiddleware --> APIClass.forbidden
    permissionsMiddleware --> APIClass.get
    permissionsMiddleware --> checkPermissionsForInvocation
    permissionsMiddleware --> Logger.error
    checkPermissions --> isLegacyPermissionsPayload
    checkPermissions --> isLightPermissionsPayload
    checkPermissions --> isPermissionsPayload
    parseDeprecation --> endpoint
    getURLWithoutSettings --> getURL_2
    APIClass.shouldVerifyRateLimit --> APIClass.get
    APIClass.namedRoutes --> APIClass.getFullRouteName
    APIClass.authenticatedRoute --> hashLoginToken
    APIClass.authenticatedRoute --> APIClass.method
    APIClass.authenticatedRoute --> APIClass.get
    APIClass.authenticatedRoute --> getDefaultUserFields
    Logger.error --> Logger.error
Loading
Fix with AI

Open in Cursor Open in Claude

Fix the following security vulnerability found by Hacktron.

File: apps/meteor/app/api/server/v1/chat.ts
Lines: 549-559
Severity: medium

Vulnerability: Missing Authorization Check in chat.starMessage/unStarMessage

Description:
The `chat.starMessage` and `chat.unStarMessage` endpoints allow a user to star or unstar any message by providing its `messageId`. The implementation retrieves the message from the database and passes it to the `starMessage` function without verifying if the authenticated user has access to the room where the message resides. An attacker could potentially star/unstar messages in rooms they are not authorized to access.

Fix this vulnerability. Only change what's necessary - don't modify unrelated code.

Triage: Reply !fp <reason> (false positive), !valid (confirmed), or !accepted_risk <reason>. Reason is optional but improves future scans — e.g. !fp internal endpoint, not user-facing. Any other reply is saved as a triage note.

View finding in Hacktron

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/meteor/app/lib/server/methods/joinRoom.ts`:
- Line 19: The deprecation log call methodDeprecationLogger.method('joinRoom',
'9.0.0', '/v1/channels.join') is too broad for the multi-room joinRoom method;
update joinRoom so you resolve the room type (e.g., using the existing room
resolution logic inside the joinRoom handler) and only call
methodDeprecationLogger.method with the specific channels route when the
resolved type is a public channel, otherwise either skip the deprecation log or
emit a type-appropriate/generic message; locate the deprecation call inside
joinRoom and gate it behind the room-type check (or replace with a no-op for
non-channel types).

In
`@apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx`:
- Line 74: The call to markThreadRead in ThreadChat.tsx is fire-and-forget and
can produce an unhandled rejection; update the invocation (the void
markThreadRead({ rid: room._id, tmid: mainMessage._id }) call) to attach a
rejection handler (e.g. .catch(() => undefined) or log the error) so promise
rejections are swallowed/handled consistently with useThreadMessagesQuery.ts;
locate markThreadRead (from useEndpoint('POST', '/v1/subscriptions.read')) in
ThreadChat and modify the call to add the .catch handler.

In `@apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts`:
- Around line 29-32: In useLoadMissedMessages, besides processing result.updated
with upsertMessage(mapMessageFromApi(...)), also handle result.deleted by
iterating over each deleted entry and removing/hiding that message from local
state (e.g., call Messages.state.delete(deleted._id) or the app’s equivalent
deletion method for each deleted._id) so deleted messages from chat.syncMessages
are not left stale after reconnect; keep the existing subscription lookup and
ensure deletions run before/after updates in a sensible order to avoid race
conditions.

In `@packages/rest-typings/src/v1/misc.ts`:
- Around line 82-87: The parser parseSpotlightType currently returns any object
including arrays; update its success check to only accept plain objects by
rejecting arrays and non-plain prototypes: after JSON.parse(parsed) assert
parsed && typeof parsed === 'object' && !Array.isArray(parsed) &&
(Object.getPrototypeOf(parsed) === Object.prototype || parsed.constructor ===
Object) before returning, otherwise return undefined; keep the function name
parseSpotlightType and the SpotlightType type for clarity.

In `@packages/rest-typings/src/v1/subscriptionsEndpoints.ts`:
- Around line 54-57: The runtime schema for the tmid field allows null (tmid: {
type: 'string', nullable: true }) but the TypeScript contract declares tmid as
optional with type IMessage['_id'] (tmid?: IMessage['_id']) which does not
include null; update the runtime validation to match the TS contract by removing
nullable: true for the tmid schema entries (both occurrences) or change the
TypeScript type to include null if null is intended—ensure the schema and the
IMessage['_id'] usage (tmid) are consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fdc65248-93ac-4e65-aa3d-183950fc83b8

📥 Commits

Reviewing files that changed from the base of the PR and between 82aad55 and b33be12.

📒 Files selected for processing (23)
  • apps/meteor/app/api/server/v1/chat.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/subscriptions.ts
  • apps/meteor/app/lib/server/methods/joinRoom.ts
  • apps/meteor/client/hooks/useJoinRoom.ts
  • apps/meteor/client/lib/chats/data.ts
  • apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts
  • apps/meteor/client/startup/startup.ts
  • apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useDeleteFile.tsx
  • apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx
  • apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
  • apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
  • apps/meteor/server/methods/deleteFileMessage.ts
  • apps/meteor/server/methods/loadMissedMessages.ts
  • apps/meteor/server/methods/readThreads.ts
  • apps/meteor/server/methods/saveUserPreferences.ts
  • apps/meteor/server/methods/userSetUtcOffset.ts
  • apps/meteor/server/publications/spotlight.ts
  • packages/rest-typings/src/v1/chat.ts
  • packages/rest-typings/src/v1/misc.ts
  • packages/rest-typings/src/v1/subscriptionsEndpoints.ts
  • packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Hacktron Security Check
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/server/methods/readThreads.ts
  • apps/meteor/client/lib/chats/data.ts
  • apps/meteor/server/methods/userSetUtcOffset.ts
  • apps/meteor/server/methods/deleteFileMessage.ts
  • apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts
  • apps/meteor/app/api/server/v1/chat.ts
  • apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts
  • packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts
  • apps/meteor/server/methods/loadMissedMessages.ts
  • apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
  • apps/meteor/client/startup/startup.ts
  • apps/meteor/app/lib/server/methods/joinRoom.ts
  • apps/meteor/server/publications/spotlight.ts
  • apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx
  • apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useDeleteFile.tsx
  • packages/rest-typings/src/v1/chat.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
  • apps/meteor/app/api/server/v1/subscriptions.ts
  • apps/meteor/client/hooks/useJoinRoom.ts
  • packages/rest-typings/src/v1/misc.ts
  • packages/rest-typings/src/v1/subscriptionsEndpoints.ts
  • apps/meteor/server/methods/saveUserPreferences.ts
🧠 Learnings (11)
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/server/methods/readThreads.ts
  • apps/meteor/client/lib/chats/data.ts
  • apps/meteor/server/methods/userSetUtcOffset.ts
  • apps/meteor/server/methods/deleteFileMessage.ts
  • apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts
  • apps/meteor/app/api/server/v1/chat.ts
  • apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts
  • packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts
  • apps/meteor/server/methods/loadMissedMessages.ts
  • apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
  • apps/meteor/client/startup/startup.ts
  • apps/meteor/app/lib/server/methods/joinRoom.ts
  • apps/meteor/server/publications/spotlight.ts
  • packages/rest-typings/src/v1/chat.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/subscriptions.ts
  • apps/meteor/client/hooks/useJoinRoom.ts
  • packages/rest-typings/src/v1/misc.ts
  • packages/rest-typings/src/v1/subscriptionsEndpoints.ts
  • apps/meteor/server/methods/saveUserPreferences.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/server/methods/readThreads.ts
  • apps/meteor/client/lib/chats/data.ts
  • apps/meteor/server/methods/userSetUtcOffset.ts
  • apps/meteor/server/methods/deleteFileMessage.ts
  • apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts
  • apps/meteor/app/api/server/v1/chat.ts
  • apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts
  • packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts
  • apps/meteor/server/methods/loadMissedMessages.ts
  • apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
  • apps/meteor/client/startup/startup.ts
  • apps/meteor/app/lib/server/methods/joinRoom.ts
  • apps/meteor/server/publications/spotlight.ts
  • packages/rest-typings/src/v1/chat.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/subscriptions.ts
  • apps/meteor/client/hooks/useJoinRoom.ts
  • packages/rest-typings/src/v1/misc.ts
  • packages/rest-typings/src/v1/subscriptionsEndpoints.ts
  • apps/meteor/server/methods/saveUserPreferences.ts
📚 Learning: 2026-03-09T18:39:14.020Z
Learnt from: Harxhit
Repo: RocketChat/Rocket.Chat PR: 39476
File: apps/meteor/server/methods/addAllUserToRoom.ts:0-0
Timestamp: 2026-03-09T18:39:14.020Z
Learning: When implementing batch processing in server methods, favor a single data pass to collect both the items and any derived fields needed for validation. Use the same dataset for both validation and processing to avoid races between validation and execution, and document the approach in code comments. Apply this pattern to similar Meteor Rocket.Chat server methods under apps/meteor/server/methods to prevent race conditions and ensure consistent batch behavior.

Applied to files:

  • apps/meteor/server/methods/readThreads.ts
  • apps/meteor/server/methods/userSetUtcOffset.ts
  • apps/meteor/server/methods/deleteFileMessage.ts
  • apps/meteor/server/methods/loadMissedMessages.ts
  • apps/meteor/server/methods/saveUserPreferences.ts
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.

Applied to files:

  • apps/meteor/server/methods/readThreads.ts
  • apps/meteor/client/lib/chats/data.ts
  • apps/meteor/server/methods/userSetUtcOffset.ts
  • apps/meteor/server/methods/deleteFileMessage.ts
  • apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts
  • apps/meteor/app/api/server/v1/chat.ts
  • apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts
  • packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts
  • apps/meteor/server/methods/loadMissedMessages.ts
  • apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
  • apps/meteor/client/startup/startup.ts
  • apps/meteor/app/lib/server/methods/joinRoom.ts
  • apps/meteor/server/publications/spotlight.ts
  • apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx
  • apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useDeleteFile.tsx
  • packages/rest-typings/src/v1/chat.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
  • apps/meteor/app/api/server/v1/subscriptions.ts
  • apps/meteor/client/hooks/useJoinRoom.ts
  • packages/rest-typings/src/v1/misc.ts
  • packages/rest-typings/src/v1/subscriptionsEndpoints.ts
  • apps/meteor/server/methods/saveUserPreferences.ts
📚 Learning: 2026-02-10T16:32:42.586Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38528
File: apps/meteor/client/startup/roles.ts:14-14
Timestamp: 2026-02-10T16:32:42.586Z
Learning: In Rocket.Chat's Meteor client code, DDP streams use EJSON and Date fields arrive as Date objects; do not manually construct new Date() in stream handlers (for example, in sdk.stream()). Only REST API responses return plain JSON where dates are strings, so implement explicit conversion there if needed. Apply this guidance to all TypeScript files under apps/meteor/client to ensure consistent date handling in DDP streams and REST responses.

Applied to files:

  • apps/meteor/client/lib/chats/data.ts
  • apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts
  • apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts
  • apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
  • apps/meteor/client/startup/startup.ts
  • apps/meteor/client/hooks/useJoinRoom.ts
📚 Learning: 2026-05-11T20:30:35.265Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 40480
File: apps/meteor/client/meteor/startup/accounts.ts:59-61
Timestamp: 2026-05-11T20:30:35.265Z
Learning: In Rocket.Chat’s Meteor client code, when calling `dispatchToastMessage` with `{ type: 'error' }`, pass the raw caught error object as `message` without manual normalization. `dispatchToastMessage` is designed to accept `message: unknown` for error toasts, so avoid converting errors to strings (e.g., `String(error)`) or extracting `error.message` before passing them.

Applied to files:

  • apps/meteor/client/lib/chats/data.ts
  • apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts
  • apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts
  • apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
  • apps/meteor/client/startup/startup.ts
  • apps/meteor/client/hooks/useJoinRoom.ts
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.

Applied to files:

  • apps/meteor/app/api/server/v1/chat.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/subscriptions.ts
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.

Applied to files:

  • apps/meteor/app/api/server/v1/chat.ts
  • apps/meteor/app/api/server/v1/misc.ts
  • apps/meteor/app/api/server/v1/subscriptions.ts
📚 Learning: 2026-05-11T23:14:59.316Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 40469
File: packages/rest-typings/src/v1/users.ts:337-337
Timestamp: 2026-05-11T23:14:59.316Z
Learning: In Rocket.Chat REST endpoint typings (e.g., packages/rest-typings/src/v1/users.ts and other rest-typings files), keep the established convention of deriving field types from the domain model (e.g., use IUser indexed access like IUser['statusExpiresAt']) rather than swapping individual fields to serialized primitives (like string) in an ad-hoc way. If a truly different “serialized” representation is needed, perform the refactor consistently across the codebase (not just a single endpoint/field) and ensure all related REST typings stay aligned with the shared serialization types.

Applied to files:

  • packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts
  • packages/rest-typings/src/v1/chat.ts
  • packages/rest-typings/src/v1/misc.ts
  • packages/rest-typings/src/v1/subscriptionsEndpoints.ts
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.

Applied to files:

  • apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx
  • apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useDeleteFile.tsx
  • apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx
📚 Learning: 2026-04-14T21:10:31.855Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 36292
File: apps/meteor/client/hooks/useHasValidLocationHash.ts:7-12
Timestamp: 2026-04-14T21:10:31.855Z
Learning: When reviewing files in apps/meteor/client/hooks/, do not treat JSDoc-style comments on React hooks (especially exported hooks) as a violation of any “avoid code comments in implementation” guideline. It’s acceptable to use JSDoc to document the public API of exported hooks (e.g., parameter/return types, intended usage), as long as it documents behavior/contracts rather than adding narrative implementation comments.

Applied to files:

  • apps/meteor/client/hooks/useJoinRoom.ts
🔇 Additional comments (21)
apps/meteor/client/hooks/useJoinRoom.ts (1)

1-34: LGTM!

apps/meteor/client/lib/chats/data.ts (1)

276-281: LGTM!

apps/meteor/client/navbar/NavBarSearch/hooks/useSearchItems.ts (1)

3-3: LGTM!

Also applies to: 50-50, 60-64

apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx (1)

6-6: LGTM!

Also applies to: 73-73, 142-147, 186-190, 412-412

packages/rest-typings/src/v1/chat.ts (1)

221-230: LGTM!

Also applies to: 241-243, 249-249

packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts (1)

56-56: LGTM!

Also applies to: 272-275

apps/meteor/app/api/server/v1/chat.ts (1)

549-552: LGTM!

Also applies to: 555-556, 559-559

apps/meteor/app/api/server/v1/subscriptions.ts (1)

2-2: LGTM!

Also applies to: 17-17, 143-143, 151-158

apps/meteor/server/methods/saveUserPreferences.ts (1)

56-56: LGTM!

Also applies to: 132-132, 156-160

apps/meteor/app/api/server/v1/misc.ts (1)

392-395: Recheck anonymous access enforcement for the spotlight endpoint

  • apps/meteor/app/api/server/v1/misc.ts sets authRequired: false (lines ~392–395, also ~406–412), so unauthenticated requests can reach the endpoint.
  • On the server side, apps/meteor/server/publications/spotlight.ts defines the Meteor method spotlight with userId(/* userId*/) { return true; }, and spotlightMethod forwards userId: this.userId into spotlight.searchUsers(...) / spotlight.searchRooms(...).
  • In the inspected apps/meteor/server/publications/spotlight.ts, there are no references to Accounts_AllowAnonymousRead/AllowAnonymousRead (or equivalent) before returning results.

Ensure the permission gating (e.g., Accounts_AllowAnonymousRead or equivalent) is enforced inside Spotlight.searchUsers/Spotlight.searchRooms (or earlier in the call chain); otherwise this change likely exposes searchable data anonymously.

apps/meteor/app/lib/server/methods/joinRoom.ts (1)

8-9: LGTM!

apps/meteor/server/methods/deleteFileMessage.ts (1)

9-9: LGTM!

Also applies to: 20-20

apps/meteor/server/methods/loadMissedMessages.ts (1)

8-8: LGTM!

Also applies to: 19-19

apps/meteor/server/methods/readThreads.ts (1)

8-8: LGTM!

Also applies to: 22-22

apps/meteor/server/methods/userSetUtcOffset.ts (1)

7-8: LGTM!

Also applies to: 18-18

apps/meteor/server/publications/spotlight.ts (1)

5-5: LGTM!

Also applies to: 72-72

apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useDeleteFile.tsx (1)

4-4: LGTM!

Also applies to: 11-11, 16-16

apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx (1)

5-5: LGTM!

Also applies to: 65-65, 83-83

apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts (1)

2-2: LGTM!

Also applies to: 29-29, 111-111

apps/meteor/client/startup/startup.ts (1)

36-36: LGTM!

Also applies to: 60-60

apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts (1)

6-7: LGTM!


Meteor.methods<ServerMethods>({
async joinRoom(rid, code) {
methodDeprecationLogger.method('joinRoom', '9.0.0', '/v1/channels.join');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Deprecation target is too broad for a multi-room joinRoom method.

joinRoom is used for more than public channels, but this log always points to /v1/channels.join. That replacement is not valid for all room types, so this warning can mislead integrators and create migration breakage when DDP is removed. Please gate the deprecation route by resolved room type (or avoid logging for unsupported non-channel types).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/app/lib/server/methods/joinRoom.ts` at line 19, The deprecation
log call methodDeprecationLogger.method('joinRoom', '9.0.0',
'/v1/channels.join') is too broad for the multi-room joinRoom method; update
joinRoom so you resolve the room type (e.g., using the existing room resolution
logic inside the joinRoom handler) and only call methodDeprecationLogger.method
with the specific channels route when the resolved type is a public channel,
otherwise either skip the deprecation log or emit a type-appropriate/generic
message; locate the deprecation call inside joinRoom and gate it behind the
room-type check (or replace with a no-op for non-channel types).

}

readThreads(mainMessage._id);
void markThreadRead({ rid: room._id, tmid: mainMessage._id });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking `useEndpoint` typing and current `subscriptions.read` call patterns..."
rg -nP --type=ts "function useEndpoint|const useEndpoint|type.*useEndpoint" apps packages -C2 || true
rg -nP --type=ts "subscriptions\.read" apps/meteor/client -C2 || true
rg -nP --type=ts "void\s+markThreadRead\s*\(" apps/meteor/client/views/room/contextualBar/Threads -C2 || true

Repository: RocketChat/Rocket.Chat

Length of output: 6109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,140p' apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx | nl -ba | sed -n '50,110p'
echo "---- useThreadMessagesQuery.ts around markThreadRead catch ----"
sed -n '80,150p' apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts | nl -ba | sed -n '90,140p'
echo "---- useEndpoint.ts implementation ----"
sed -n '1,120p' packages/ui-contexts/src/hooks/useEndpoint.ts | nl -ba | sed -n '1,120p'

Repository: RocketChat/Rocket.Chat

Length of output: 109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,140p' apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx | nl -ba | sed -n '50,110p'
echo "---- useThreadMessagesQuery.ts around markThreadRead catch ----"
sed -n '80,160p' apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts | nl -ba | sed -n '90,150p'
echo "---- useEndpoint.ts implementation ----"
sed -n '1,160p' packages/ui-contexts/src/hooks/useEndpoint.ts | nl -ba | sed -n '1,160p'

Repository: RocketChat/Rocket.Chat

Length of output: 109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,140p' apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx | nl -ba | sed -n '50,110p'
echo "---- useThreadMessagesQuery.ts around markThreadRead catch ----"
sed -n '90,140p' apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts | nl -ba | sed -n '90,140p'
echo "---- useEndpoint.ts implementation ----"
sed -n '1,200p' packages/ui-contexts/src/hooks/useEndpoint.ts | nl -ba | sed -n '1,200p'

Repository: RocketChat/Rocket.Chat

Length of output: 109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,160p' apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx | nl -ba | sed -n '55,95p'
echo "---- useThreadMessagesQuery.ts around markThreadRead catch ----"
sed -n '90,130p' apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts | nl -ba | sed -n '100,125p'
echo "---- useEndpoint.ts implementation ----"
sed -n '1,120p' packages/ui-contexts/src/hooks/useEndpoint.ts | nl -ba | sed -n '1,120p'

Repository: RocketChat/Rocket.Chat

Length of output: 109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- ThreadChat.tsx around markThreadRead ----"
nl -ba apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx | sed -n '55,95p'

echo "---- useThreadMessagesQuery.ts around markThreadRead catch ----"
nl -ba apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts | sed -n '95,125p'

echo "---- useEndpoint.ts implementation ----"
nl -ba packages/ui-contexts/src/hooks/useEndpoint.ts | sed -n '1,140p'

Repository: RocketChat/Rocket.Chat

Length of output: 174


Handle errors for markThreadRead fire-and-forget in ThreadChat.
markThreadRead comes from useEndpoint('POST', '/v1/subscriptions.read') (Promise-returning) and is currently dropped without a rejection handler; the same call in useThreadMessagesQuery.ts already uses .catch(() => undefined). Align ThreadChat.tsx to avoid potential unhandled promise rejections.

Proposed fix
-				void markThreadRead({ rid: room._id, tmid: mainMessage._id });
+				void markThreadRead({ rid: room._id, tmid: mainMessage._id }).catch(() => undefined);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void markThreadRead({ rid: room._id, tmid: mainMessage._id });
void markThreadRead({ rid: room._id, tmid: mainMessage._id }).catch(() => undefined);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx`
at line 74, The call to markThreadRead in ThreadChat.tsx is fire-and-forget and
can produce an unhandled rejection; update the invocation (the void
markThreadRead({ rid: room._id, tmid: mainMessage._id }) call) to attach a
rejection handler (e.g. .catch(() => undefined) or log the error) so promise
rejections are swallowed/handled consistently with useThreadMessagesQuery.ts;
locate markThreadRead (from useEndpoint('POST', '/v1/subscriptions.read')) in
ThreadChat and modify the call to add the .catch handler.

Comment thread apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
Comment on lines +82 to +87
const parseSpotlightType = (raw?: string): SpotlightType | undefined => {
if (!raw) return undefined;
try {
const parsed = JSON.parse(raw) as SpotlightType;
return parsed && typeof parsed === 'object' ? parsed : undefined;
} catch {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tighten type parser to reject arrays/non-plain objects.

parseSpotlightType currently accepts [] because typeof [] === 'object'. On Line 86, validate plain-object shape before returning.

Suggested fix
 const parseSpotlightType = (raw?: string): SpotlightType | undefined => {
 	if (!raw) return undefined;
 	try {
-		const parsed = JSON.parse(raw) as SpotlightType;
-		return parsed && typeof parsed === 'object' ? parsed : undefined;
+		const parsed = JSON.parse(raw);
+		if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
+			return undefined;
+		}
+		return parsed as SpotlightType;
 	} catch {
 		return undefined;
 	}
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const parseSpotlightType = (raw?: string): SpotlightType | undefined => {
if (!raw) return undefined;
try {
const parsed = JSON.parse(raw) as SpotlightType;
return parsed && typeof parsed === 'object' ? parsed : undefined;
} catch {
const parseSpotlightType = (raw?: string): SpotlightType | undefined => {
if (!raw) return undefined;
try {
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
return undefined;
}
return parsed as SpotlightType;
} catch {
return undefined;
}
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rest-typings/src/v1/misc.ts` around lines 82 - 87, The parser
parseSpotlightType currently returns any object including arrays; update its
success check to only accept plain objects by rejecting arrays and non-plain
prototypes: after JSON.parse(parsed) assert parsed && typeof parsed === 'object'
&& !Array.isArray(parsed) && (Object.getPrototypeOf(parsed) === Object.prototype
|| parsed.constructor === Object) before returning, otherwise return undefined;
keep the function name parseSpotlightType and the SpotlightType type for
clarity.

Comment on lines +54 to +57
tmid: {
type: 'string',
nullable: true,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep runtime validation aligned with the declared TypeScript contract.

On Line 54 and Line 72, tmid is nullable: true, but the type is tmid?: IMessage['_id'] (no null). This allows payloads the public type does not advertise.

Suggested fix
 				tmid: {
 					type: 'string',
-					nullable: true,
 				},

Also applies to: 72-75

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rest-typings/src/v1/subscriptionsEndpoints.ts` around lines 54 - 57,
The runtime schema for the tmid field allows null (tmid: { type: 'string',
nullable: true }) but the TypeScript contract declares tmid as optional with
type IMessage['_id'] (tmid?: IMessage['_id']) which does not include null;
update the runtime validation to match the TS contract by removing nullable:
true for the tmid schema entries (both occurrences) or change the TypeScript
type to include null if null is intended—ensure the schema and the
IMessage['_id'] usage (tmid) are consistent.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 issues found across 23 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/api/server/v1/chat.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/chat.ts:550">
P2: Reject requests that include both `fileId` and `msgId` to avoid ambiguous delete-target resolution.</violation>
</file>

<file name="apps/meteor/app/lib/server/methods/joinRoom.ts">

<violation number="1" location="apps/meteor/app/lib/server/methods/joinRoom.ts:19">
P2: Unconditional deprecation log contradicts PR intent — `joinRoom` is still called via DDP for non-channel types (private groups, DMs, livechat) where `channels.join` does not apply. This will produce noisy deprecation warnings for legitimate DDP usage that has no REST equivalent yet. Consider either removing the log or making it conditional on room.t === 'c' after the room is fetched.</violation>
</file>

<file name="packages/rest-typings/src/v1/chat.ts">

<violation number="1" location="packages/rest-typings/src/v1/chat.ts:249">
P2: Use `oneOf` (or make the branches mutually exclusive) so mixed `fileId` + `msgId`/`roomId` payloads are rejected instead of silently taking the file-id branch.

(Based on your team's feedback about keeping API typings aligned with runtime endpoints.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/meteor/client/hooks/useJoinRoom.ts">

<violation number="1" location="apps/meteor/client/hooks/useJoinRoom.ts:22">
P1: Preserve the DDP fallback here. This mutation ignores `type` and always posts to `/v1/channels.join`, so the join button now fails for room types outside the REST route's accepted set.</violation>
</file>

<file name="apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts">

<violation number="1" location="apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts:29">
P1: Handle `result.deleted` as well as `result.updated`; otherwise offline deletions are never reflected in the client store.</violation>
</file>

<file name="apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx">

<violation number="1" location="apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx:74">
P3: Add `.catch(() => undefined)` to suppress potential unhandled promise rejections—this matches the pattern already used for the same `markThreadRead` call in `useThreadMessagesQuery.ts`.</violation>
</file>

<file name="packages/rest-typings/src/v1/misc.ts">

<violation number="1" location="packages/rest-typings/src/v1/misc.ts:86">
P3: `typeof [] === 'object'` in JavaScript, so this check would accept an array as a valid `SpotlightType`. Add `Array.isArray(parsed)` guard to reject non-plain-object inputs.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/meteor/client/hooks/useJoinRoom.ts
Comment thread apps/meteor/client/views/root/hooks/useLoadMissedMessages.ts
Comment on lines +550 to 553
'fileId' in this.bodyParams
? await Messages.getMessageByFileId(this.bodyParams.fileId)
: await Messages.findOneById(this.bodyParams.msgId, { projection: { u: 1, rid: 1 } });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Reject requests that include both fileId and msgId to avoid ambiguous delete-target resolution.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/app/api/server/v1/chat.ts, line 550:

<comment>Reject requests that include both `fileId` and `msgId` to avoid ambiguous delete-target resolution.</comment>

<file context>
@@ -546,13 +546,17 @@ const chatEndpoints = API.v1
 		async function action() {
-			const msg = await Messages.findOneById(this.bodyParams.msgId, { projection: { u: 1, rid: 1 } });
+			const msg =
+				'fileId' in this.bodyParams
+					? await Messages.getMessageByFileId(this.bodyParams.fileId)
+					: await Messages.findOneById(this.bodyParams.msgId, { projection: { u: 1, rid: 1 } });
</file context>
Suggested change
'fileId' in this.bodyParams
? await Messages.getMessageByFileId(this.bodyParams.fileId)
: await Messages.findOneById(this.bodyParams.msgId, { projection: { u: 1, rid: 1 } });
if ('fileId' in this.bodyParams && 'msgId' in this.bodyParams) {
return API.v1.failure('Provide either "fileId" or "msgId"/"roomId", not both.');
}
const msg =
'fileId' in this.bodyParams
? await Messages.getMessageByFileId(this.bodyParams.fileId)
: await Messages.findOneById(this.bodyParams.msgId, { projection: { u: 1, rid: 1 } });


Meteor.methods<ServerMethods>({
async joinRoom(rid, code) {
methodDeprecationLogger.method('joinRoom', '9.0.0', '/v1/channels.join');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Unconditional deprecation log contradicts PR intent — joinRoom is still called via DDP for non-channel types (private groups, DMs, livechat) where channels.join does not apply. This will produce noisy deprecation warnings for legitimate DDP usage that has no REST equivalent yet. Consider either removing the log or making it conditional on room.t === 'c' after the room is fetched.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/app/lib/server/methods/joinRoom.ts, line 19:

<comment>Unconditional deprecation log contradicts PR intent — `joinRoom` is still called via DDP for non-channel types (private groups, DMs, livechat) where `channels.join` does not apply. This will produce noisy deprecation warnings for legitimate DDP usage that has no REST equivalent yet. Consider either removing the log or making it conditional on room.t === 'c' after the room is fetched.</comment>

<file context>
@@ -14,6 +16,7 @@ declare module '@rocket.chat/ddp-client' {
 
 Meteor.methods<ServerMethods>({
 	async joinRoom(rid, code) {
+		methodDeprecationLogger.method('joinRoom', '9.0.0', '/v1/channels.join');
 		check(rid, String);
 
</file context>

},
},
required: ['msgId', 'roomId'],
anyOf: [{ required: ['msgId', 'roomId'] }, { required: ['fileId'] }],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use oneOf (or make the branches mutually exclusive) so mixed fileId + msgId/roomId payloads are rejected instead of silently taking the file-id branch.

(Based on your team's feedback about keeping API typings aligned with runtime endpoints.)

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/rest-typings/src/v1/chat.ts, line 249:

<comment>Use `oneOf` (or make the branches mutually exclusive) so mixed `fileId` + `msgId`/`roomId` payloads are rejected instead of silently taking the file-id branch.

(Based on your team's feedback about keeping API typings aligned with runtime endpoints.) </comment>

<file context>
@@ -233,12 +238,15 @@ const ChatDeleteSchema = {
 		},
 	},
-	required: ['msgId', 'roomId'],
+	anyOf: [{ required: ['msgId', 'roomId'] }, { required: ['fileId'] }],
 	additionalProperties: false,
 };
</file context>
Suggested change
anyOf: [{ required: ['msgId', 'roomId'] }, { required: ['fileId'] }],
oneOf: [{ required: ['msgId', 'roomId'] }, { required: ['fileId'] }],

}

readThreads(mainMessage._id);
void markThreadRead({ rid: room._id, tmid: mainMessage._id });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Add .catch(() => undefined) to suppress potential unhandled promise rejections—this matches the pattern already used for the same markThreadRead call in useThreadMessagesQuery.ts.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx, line 74:

<comment>Add `.catch(() => undefined)` to suppress potential unhandled promise rejections—this matches the pattern already used for the same `markThreadRead` call in `useThreadMessagesQuery.ts`.</comment>

<file context>
@@ -71,7 +71,7 @@ const ThreadChat = ({ mainMessage }: ThreadChatProps) => {
 				}
 
-				readThreads(mainMessage._id);
+				void markThreadRead({ rid: room._id, tmid: mainMessage._id });
 			},
 			clientCallbacks.priority.MEDIUM,
</file context>
Suggested change
void markThreadRead({ rid: room._id, tmid: mainMessage._id });
void markThreadRead({ rid: room._id, tmid: mainMessage._id }).catch(() => undefined);

if (!raw) return undefined;
try {
const parsed = JSON.parse(raw) as SpotlightType;
return parsed && typeof parsed === 'object' ? parsed : undefined;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: typeof [] === 'object' in JavaScript, so this check would accept an array as a valid SpotlightType. Add Array.isArray(parsed) guard to reject non-plain-object inputs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/rest-typings/src/v1/misc.ts, line 86:

<comment>`typeof [] === 'object'` in JavaScript, so this check would accept an array as a valid `SpotlightType`. Add `Array.isArray(parsed)` guard to reject non-plain-object inputs.</comment>

<file context>
@@ -38,21 +38,60 @@ const ShieldSvgSchema = {
+	if (!raw) return undefined;
+	try {
+		const parsed = JSON.parse(raw) as SpotlightType;
+		return parsed && typeof parsed === 'object' ? parsed : undefined;
+	} catch {
+		return undefined;
</file context>
Suggested change
return parsed && typeof parsed === 'object' ? parsed : undefined;
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
return undefined;
}
return parsed as SpotlightType;

@hacktron-app hacktron-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Severity Count
🟡 Medium 1

View full scan results

@ggazzo ggazzo changed the title chore: migrate loadMissedMessages and joinRoom (channel) DDP callers to REST feat: extend 4 REST endpoints + migrate 7 DDP callers May 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/core-typings/src/IUser.ts (1)

236-238: IUser: providerId removal looks safe for in-repo runtime code (no user-providerId usages found).

  • packages/core-typings/src/IUser.ts no longer defines providerId.
  • Repo searches for IUser/user-document access via providerId (e.g., user/IUser.providerId, ['providerId'], and Mongo ops on users) returned no matches; remaining providerId hits are for outbound provider metadata (e.g., apps/meteor/client/lib/queryKeys.ts).
  • Remaining risk is limited to external consumers of the typings and any historical persisted user documents that may still contain providerId—ensure nothing still reads it (migration/cleanup only if needed).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core-typings/src/IUser.ts` around lines 236 - 238, IUser no longer
declares providerId which may break external consumers or code reading
historical persisted user docs; add a clear JSDoc/deprecation comment in the
IUser declaration explaining that providerId was intentionally removed, note the
expected migration/cleanup for persisted user documents, and document this
breaking change in the package changelog/release notes so consumers know to
migrate or re-add an optional providerId if needed (refer to the IUser type and
the providerId field).
apps/meteor/server/lib/oauth/updateOAuthServices.ts (1)

71-96: ⚡ Quick win

Re-check CustomOAuth instantiation on settings updates

  • Although updateOAuthServices calls new CustomOAuth(serviceKey, ...) each time, CustomOAuth uses a module-level Services map: if Services[name] already exists, the constructor only runs Services[name].configure(options) and returns before re-registering service/hooks.
  • Optional: if you want to reduce per-update allocations and make intent clearer, add a dedicated configure/factory path (or cache the instance) so callers don’t construct throwaway objects.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/meteor/server/lib/oauth/updateOAuthServices.ts` around lines 71 - 96,
The current updateOAuthServices flow repeatedly calls new
CustomOAuth(serviceKey, ...) even though CustomOAuth's constructor checks the
module-level Services[name] and simply calls Services[name].configure(options)
if already present; change updateOAuthServices to call a dedicated configure
path instead of allocating throwaway objects: add or use an exported
configure(name, options) function (or a factory like
CustomOAuth.configure/serviceConfigure) that looks up Services[serviceKey] and
calls .configure(options) or creates and registers a new instance if missing;
update the call site (updateOAuthServices) to invoke that configure function
with serviceKey and the options object rather than instantiating CustomOAuth
with new each update to make intent explicit and avoid unnecessary allocations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/meteor/app/apple/lib/handleIdentityToken.ts`:
- Around line 46-50: handleIdentityToken.ts currently sets serviceData.name = ''
which can overwrite an existing user display name on subsequent logins; modify
the flow so an empty name is not persisted — either omit the name property from
the returned identity payload or set it to undefined instead of an empty string,
and ensure AppleCustomOAuth.ts only assigns serviceData.name when the
authorization response contains usrObj.name (firstName/lastName) so you never
send an explicit empty name down to custom_oauth_server.js where it would
overwrite an existing display name.

In `@apps/meteor/app/apple/server/appleOauthRegisterService.ts`:
- Around line 50-61: Before calling KJUR.jws.JWS.sign, guard against an empty or
invalid ES256 private key by validating serverSecret and handling signing
errors: check serverSecret is a non-empty string and optionally verify it
matches expected PEM/JWK/EC key pattern, then wrap the KJUR.jws.JWS.sign call
(the block that produces secret using HEADER, iss, iat, exp, aud, sub,
serverSecret) in a try/catch; on failure log a clear admin-facing error
(including the exception message) and throw or return a controlled error instead
of letting the exception bubble uncaught.

In `@apps/meteor/app/apple/server/loginHandler.ts`:
- Around line 32-35: The call to
Accounts.updateOrCreateUserFromExternalService('apple', serviceData, { profile
}) returns a Promise, so add await before this call to get the resolved result
and then check result.userId; ensure the enclosing function (the Apple login
handler) is declared async if it isn't already so awaiting is valid, and keep
existing error handling that throws "User creation failed" when the awaited
result is undefined or has no userId.

---

Nitpick comments:
In `@apps/meteor/server/lib/oauth/updateOAuthServices.ts`:
- Around line 71-96: The current updateOAuthServices flow repeatedly calls new
CustomOAuth(serviceKey, ...) even though CustomOAuth's constructor checks the
module-level Services[name] and simply calls Services[name].configure(options)
if already present; change updateOAuthServices to call a dedicated configure
path instead of allocating throwaway objects: add or use an exported
configure(name, options) function (or a factory like
CustomOAuth.configure/serviceConfigure) that looks up Services[serviceKey] and
calls .configure(options) or creates and registers a new instance if missing;
update the call site (updateOAuthServices) to invoke that configure function
with serviceKey and the options object rather than instantiating CustomOAuth
with new each update to make intent explicit and avoid unnecessary allocations.

In `@packages/core-typings/src/IUser.ts`:
- Around line 236-238: IUser no longer declares providerId which may break
external consumers or code reading historical persisted user docs; add a clear
JSDoc/deprecation comment in the IUser declaration explaining that providerId
was intentionally removed, note the expected migration/cleanup for persisted
user documents, and document this breaking change in the package
changelog/release notes so consumers know to migrate or re-add an optional
providerId if needed (refer to the IUser type and the providerId field).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: da294d22-7d16-42bb-81dc-99bf5593e105

📥 Commits

Reviewing files that changed from the base of the PR and between b33be12 and f4c9d38.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (76)
  • .changeset/flat-poets-cheat.md
  • apps/meteor/app/2fa/server/code/EmailCheck.ts
  • apps/meteor/app/2fa/server/code/EmailCheckForOAuth.ts
  • apps/meteor/app/2fa/server/code/TOTPCheck.ts
  • apps/meteor/app/2fa/server/code/TOTPCheckForOAuth.ts
  • apps/meteor/app/2fa/server/code/index.ts
  • apps/meteor/app/api/server/ApiClass.ts
  • apps/meteor/app/api/server/index.ts
  • apps/meteor/app/api/server/v1/twoFactorChallenges.ts
  • apps/meteor/app/apple/lib/handleIdentityToken.ts
  • apps/meteor/app/apple/server/appleOauthRegisterService.ts
  • apps/meteor/app/apple/server/loginHandler.ts
  • apps/meteor/app/custom-oauth/server/customOAuth.ts
  • apps/meteor/app/custom-oauth/server/custom_oauth_server.js
  • apps/meteor/app/custom-sounds/server/methods/listCustomSounds.ts
  • apps/meteor/app/dolphin/server/lib.ts
  • apps/meteor/app/drupal/server/lib.ts
  • apps/meteor/app/gitlab/server/lib.ts
  • apps/meteor/app/lib/server/methods/createToken.ts
  • apps/meteor/app/linkedin/server/index.ts
  • apps/meteor/app/linkedin/server/lib.ts
  • apps/meteor/app/meteor-developer/server/index.ts
  • apps/meteor/app/meteor-developer/server/lib.ts
  • apps/meteor/app/nextcloud/server/lib.ts
  • apps/meteor/app/wordpress/server/lib.ts
  • apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx
  • apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx
  • apps/meteor/client/lib/2fa/process2faReturn.ts
  • apps/meteor/client/lib/buildAuthDeeplinkURL.ts
  • apps/meteor/client/lib/sdk/ddpSdk.ts
  • apps/meteor/client/providers/CustomSoundProvider/CustomSoundProvider.tsx
  • apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts
  • apps/meteor/client/startup/routes.tsx
  • apps/meteor/client/views/OAuthTwoFactorAuthentication/OAuthTwoFactorAuthenticationRouter.tsx
  • apps/meteor/client/views/root/AppLayout.tsx
  • apps/meteor/client/views/root/hooks/useLoginOtherClients.ts
  • apps/meteor/client/views/root/hooks/useLoginViaQuery.ts
  • apps/meteor/client/views/root/hooks/useShareSessionWithOtherClients.ts
  • apps/meteor/definition/externals/express-session.d.ts
  • apps/meteor/definition/externals/express.d.ts
  • apps/meteor/definition/externals/meteor/accounts-base.d.ts
  • apps/meteor/package.json
  • apps/meteor/server/configuration/accounts_meld.js
  • apps/meteor/server/configuration/configurePassport.ts
  • apps/meteor/server/configuration/index.ts
  • apps/meteor/server/importPackages.ts
  • apps/meteor/server/lib/oauth/addPassportCustomOAuth.ts
  • apps/meteor/server/lib/oauth/configureOAuthServices.ts
  • apps/meteor/server/lib/oauth/createOAuthServiceConfig.ts
  • apps/meteor/server/lib/oauth/getOAuthServices.ts
  • apps/meteor/server/lib/oauth/oauthConfigs.ts
  • apps/meteor/server/lib/oauth/passportOAuthCallback.ts
  • apps/meteor/server/lib/oauth/twoFactorAuth.ts
  • apps/meteor/server/lib/oauth/updateOAuthServices.ts
  • apps/meteor/server/lib/oauth/verifyFunction.ts
  • apps/meteor/server/models.ts
  • apps/meteor/server/settings/oauth.ts
  • apps/meteor/tests/e2e/fixtures/addCustomOAuth.ts
  • packages/core-typings/src/ILoginServiceConfiguration.ts
  • packages/core-typings/src/ITwoFactorChallenge.ts
  • packages/core-typings/src/IUser.ts
  • packages/core-typings/src/index.ts
  • packages/desktop-api/src/index.ts
  • packages/i18n/src/locales/en.i18n.json
  • packages/model-typings/src/index.ts
  • packages/model-typings/src/models/ITwoFactorChallengesModel.ts
  • packages/models/src/index.ts
  • packages/models/src/modelClasses.ts
  • packages/models/src/models/TwoFactorChallenges.ts
  • packages/rest-typings/src/index.ts
  • packages/rest-typings/src/v1/twoFactorChallenges.ts
  • packages/web-ui-registration/global.d.ts
  • packages/web-ui-registration/src/LoginServices.tsx
  • packages/web-ui-registration/src/LoginServicesButton.tsx
  • packages/web-ui-registration/tsconfig.build.json
  • packages/web-ui-registration/tsconfig.json
💤 Files with no reviewable changes (46)
  • apps/meteor/client/lib/buildAuthDeeplinkURL.ts
  • apps/meteor/app/2fa/server/code/EmailCheckForOAuth.ts
  • .changeset/flat-poets-cheat.md
  • apps/meteor/definition/externals/express-session.d.ts
  • apps/meteor/app/2fa/server/code/TOTPCheckForOAuth.ts
  • packages/web-ui-registration/global.d.ts
  • apps/meteor/client/views/root/hooks/useShareSessionWithOtherClients.ts
  • apps/meteor/app/custom-oauth/server/custom_oauth_server.js
  • apps/meteor/server/lib/oauth/getOAuthServices.ts
  • apps/meteor/server/lib/oauth/verifyFunction.ts
  • apps/meteor/app/linkedin/server/index.ts
  • packages/rest-typings/src/v1/twoFactorChallenges.ts
  • packages/models/src/modelClasses.ts
  • apps/meteor/app/meteor-developer/server/lib.ts
  • apps/meteor/app/linkedin/server/lib.ts
  • apps/meteor/client/views/root/hooks/useLoginOtherClients.ts
  • packages/core-typings/src/ITwoFactorChallenge.ts
  • apps/meteor/app/api/server/v1/twoFactorChallenges.ts
  • apps/meteor/server/lib/oauth/oauthConfigs.ts
  • packages/models/src/models/TwoFactorChallenges.ts
  • apps/meteor/tests/e2e/fixtures/addCustomOAuth.ts
  • apps/meteor/server/lib/oauth/passportOAuthCallback.ts
  • apps/meteor/server/lib/oauth/twoFactorAuth.ts
  • apps/meteor/server/configuration/configurePassport.ts
  • apps/meteor/server/lib/oauth/createOAuthServiceConfig.ts
  • apps/meteor/client/views/OAuthTwoFactorAuthentication/OAuthTwoFactorAuthenticationRouter.tsx
  • apps/meteor/server/lib/oauth/addPassportCustomOAuth.ts
  • packages/model-typings/src/index.ts
  • apps/meteor/server/settings/oauth.ts
  • apps/meteor/definition/externals/express.d.ts
  • apps/meteor/server/configuration/index.ts
  • packages/core-typings/src/ILoginServiceConfiguration.ts
  • apps/meteor/client/startup/routes.tsx
  • packages/model-typings/src/models/ITwoFactorChallengesModel.ts
  • packages/rest-typings/src/index.ts
  • apps/meteor/app/meteor-developer/server/index.ts
  • apps/meteor/client/views/root/AppLayout.tsx
  • apps/meteor/server/lib/oauth/configureOAuthServices.ts
  • packages/core-typings/src/index.ts
  • packages/models/src/index.ts
  • packages/desktop-api/src/index.ts
  • apps/meteor/server/models.ts
  • apps/meteor/app/custom-oauth/server/customOAuth.ts
  • packages/i18n/src/locales/en.i18n.json
  • apps/meteor/package.json
  • apps/meteor/server/importPackages.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/web-ui-registration/tsconfig.json
  • apps/meteor/app/2fa/server/code/TOTPCheck.ts
  • packages/web-ui-registration/tsconfig.build.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: CodeQL-Build
  • GitHub Check: Hacktron Security Check
  • GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/apple/server/loginHandler.ts
  • apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx
  • apps/meteor/app/custom-sounds/server/methods/listCustomSounds.ts
  • apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts
  • apps/meteor/client/views/root/hooks/useLoginViaQuery.ts
  • packages/core-typings/src/IUser.ts
  • apps/meteor/app/drupal/server/lib.ts
  • apps/meteor/app/dolphin/server/lib.ts
  • apps/meteor/app/lib/server/methods/createToken.ts
  • apps/meteor/client/providers/CustomSoundProvider/CustomSoundProvider.tsx
  • apps/meteor/app/api/server/ApiClass.ts
  • apps/meteor/app/2fa/server/code/EmailCheck.ts
  • apps/meteor/definition/externals/meteor/accounts-base.d.ts
  • apps/meteor/app/gitlab/server/lib.ts
  • packages/web-ui-registration/src/LoginServicesButton.tsx
  • apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx
  • apps/meteor/app/wordpress/server/lib.ts
  • apps/meteor/app/api/server/index.ts
  • packages/web-ui-registration/src/LoginServices.tsx
  • apps/meteor/client/lib/sdk/ddpSdk.ts
  • apps/meteor/server/lib/oauth/updateOAuthServices.ts
  • apps/meteor/app/nextcloud/server/lib.ts
  • apps/meteor/app/apple/lib/handleIdentityToken.ts
  • apps/meteor/app/apple/server/appleOauthRegisterService.ts
  • apps/meteor/server/configuration/accounts_meld.js
  • apps/meteor/app/2fa/server/code/index.ts
  • apps/meteor/client/lib/2fa/process2faReturn.ts
🧠 Learnings (6)
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/apple/server/loginHandler.ts
  • apps/meteor/app/custom-sounds/server/methods/listCustomSounds.ts
  • apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts
  • apps/meteor/client/views/root/hooks/useLoginViaQuery.ts
  • packages/core-typings/src/IUser.ts
  • apps/meteor/app/drupal/server/lib.ts
  • apps/meteor/app/dolphin/server/lib.ts
  • apps/meteor/app/lib/server/methods/createToken.ts
  • apps/meteor/app/api/server/ApiClass.ts
  • apps/meteor/app/2fa/server/code/EmailCheck.ts
  • apps/meteor/definition/externals/meteor/accounts-base.d.ts
  • apps/meteor/app/gitlab/server/lib.ts
  • apps/meteor/app/wordpress/server/lib.ts
  • apps/meteor/app/api/server/index.ts
  • apps/meteor/client/lib/sdk/ddpSdk.ts
  • apps/meteor/server/lib/oauth/updateOAuthServices.ts
  • apps/meteor/app/nextcloud/server/lib.ts
  • apps/meteor/app/apple/lib/handleIdentityToken.ts
  • apps/meteor/app/apple/server/appleOauthRegisterService.ts
  • apps/meteor/app/2fa/server/code/index.ts
  • apps/meteor/client/lib/2fa/process2faReturn.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/apple/server/loginHandler.ts
  • apps/meteor/app/custom-sounds/server/methods/listCustomSounds.ts
  • apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts
  • apps/meteor/client/views/root/hooks/useLoginViaQuery.ts
  • packages/core-typings/src/IUser.ts
  • apps/meteor/app/drupal/server/lib.ts
  • apps/meteor/app/dolphin/server/lib.ts
  • apps/meteor/app/lib/server/methods/createToken.ts
  • apps/meteor/app/api/server/ApiClass.ts
  • apps/meteor/app/2fa/server/code/EmailCheck.ts
  • apps/meteor/definition/externals/meteor/accounts-base.d.ts
  • apps/meteor/app/gitlab/server/lib.ts
  • apps/meteor/app/wordpress/server/lib.ts
  • apps/meteor/app/api/server/index.ts
  • apps/meteor/client/lib/sdk/ddpSdk.ts
  • apps/meteor/server/lib/oauth/updateOAuthServices.ts
  • apps/meteor/app/nextcloud/server/lib.ts
  • apps/meteor/app/apple/lib/handleIdentityToken.ts
  • apps/meteor/app/apple/server/appleOauthRegisterService.ts
  • apps/meteor/app/2fa/server/code/index.ts
  • apps/meteor/client/lib/2fa/process2faReturn.ts
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.

Applied to files:

  • apps/meteor/app/apple/server/loginHandler.ts
  • apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx
  • apps/meteor/app/custom-sounds/server/methods/listCustomSounds.ts
  • apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts
  • apps/meteor/client/views/root/hooks/useLoginViaQuery.ts
  • packages/core-typings/src/IUser.ts
  • apps/meteor/app/drupal/server/lib.ts
  • apps/meteor/app/dolphin/server/lib.ts
  • apps/meteor/app/lib/server/methods/createToken.ts
  • apps/meteor/client/providers/CustomSoundProvider/CustomSoundProvider.tsx
  • apps/meteor/app/api/server/ApiClass.ts
  • apps/meteor/app/2fa/server/code/EmailCheck.ts
  • apps/meteor/definition/externals/meteor/accounts-base.d.ts
  • apps/meteor/app/gitlab/server/lib.ts
  • packages/web-ui-registration/src/LoginServicesButton.tsx
  • apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx
  • apps/meteor/app/wordpress/server/lib.ts
  • apps/meteor/app/api/server/index.ts
  • packages/web-ui-registration/src/LoginServices.tsx
  • apps/meteor/client/lib/sdk/ddpSdk.ts
  • apps/meteor/server/lib/oauth/updateOAuthServices.ts
  • apps/meteor/app/nextcloud/server/lib.ts
  • apps/meteor/app/apple/lib/handleIdentityToken.ts
  • apps/meteor/app/apple/server/appleOauthRegisterService.ts
  • apps/meteor/app/2fa/server/code/index.ts
  • apps/meteor/client/lib/2fa/process2faReturn.ts
📚 Learning: 2026-03-27T14:52:56.865Z
Learnt from: dougfabris
Repo: RocketChat/Rocket.Chat PR: 39892
File: apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx:150-155
Timestamp: 2026-03-27T14:52:56.865Z
Learning: In Rocket.Chat, there are two different `ModalBackdrop` components with different prop APIs. During review, confirm the import source: (1) `rocket.chat/fuselage` `ModalBackdrop` uses `ModalBackdropProps` based on `BoxProps` (so it supports `onClick` and other Box/DOM props) and does not have an `onDismiss` prop; (2) `rocket.chat/ui-client` `ModalBackdrop` uses a narrower props interface like `{ children?: ReactNode; onDismiss?: () => void }` and handles Escape keypress and outside mouse-up, and it does not forward arbitrary DOM props such as `onClick`. Flag mismatched props (e.g., `onDismiss` passed to the fuselage component or `onClick` passed to the ui-client component) and ensure the usage matches the correct component being imported.

Applied to files:

  • apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx
  • apps/meteor/client/providers/CustomSoundProvider/CustomSoundProvider.tsx
  • packages/web-ui-registration/src/LoginServicesButton.tsx
  • apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx
  • packages/web-ui-registration/src/LoginServices.tsx
📚 Learning: 2026-02-10T16:32:42.586Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38528
File: apps/meteor/client/startup/roles.ts:14-14
Timestamp: 2026-02-10T16:32:42.586Z
Learning: In Rocket.Chat's Meteor client code, DDP streams use EJSON and Date fields arrive as Date objects; do not manually construct new Date() in stream handlers (for example, in sdk.stream()). Only REST API responses return plain JSON where dates are strings, so implement explicit conversion there if needed. Apply this guidance to all TypeScript files under apps/meteor/client to ensure consistent date handling in DDP streams and REST responses.

Applied to files:

  • apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts
  • apps/meteor/client/views/root/hooks/useLoginViaQuery.ts
  • apps/meteor/client/lib/sdk/ddpSdk.ts
  • apps/meteor/client/lib/2fa/process2faReturn.ts
📚 Learning: 2026-05-11T20:30:35.265Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 40480
File: apps/meteor/client/meteor/startup/accounts.ts:59-61
Timestamp: 2026-05-11T20:30:35.265Z
Learning: In Rocket.Chat’s Meteor client code, when calling `dispatchToastMessage` with `{ type: 'error' }`, pass the raw caught error object as `message` without manual normalization. `dispatchToastMessage` is designed to accept `message: unknown` for error toasts, so avoid converting errors to strings (e.g., `String(error)`) or extracting `error.message` before passing them.

Applied to files:

  • apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts
  • apps/meteor/client/views/root/hooks/useLoginViaQuery.ts
  • apps/meteor/client/lib/sdk/ddpSdk.ts
  • apps/meteor/client/lib/2fa/process2faReturn.ts
🔇 Additional comments (29)
apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx (1)

24-36: LGTM!

apps/meteor/app/custom-sounds/server/methods/listCustomSounds.ts (1)

6-7: LGTM!

Also applies to: 17-17

apps/meteor/client/providers/CustomSoundProvider/lib/helpers.ts (1)

7-9: LGTM!

apps/meteor/client/views/root/hooks/useLoginViaQuery.ts (1)

10-14: LGTM!

apps/meteor/app/drupal/server/lib.ts (1)

1-33: LGTM!

apps/meteor/app/dolphin/server/lib.ts (1)

1-54: LGTM!

apps/meteor/app/lib/server/methods/createToken.ts (1)

19-21: LGTM!

apps/meteor/client/providers/CustomSoundProvider/CustomSoundProvider.tsx (1)

3-3: LGTM!

Also applies to: 19-19, 25-35

apps/meteor/app/2fa/server/code/EmailCheck.ts (2)

13-13: LGTM!


146-149: 💤 Low value

Remove/justify the as boolean cast in EmailCheck.ts.

maxFaildedAttemtpsReached casts await Users.maxInvalidEmailCodeAttemptsReached(...) to boolean; if the model already returns Promise<boolean>, the cast is redundant. If not, the cast can hide a real type mismatch—confirm the model’s return type and either drop the assertion or fix the model signature.

apps/meteor/app/gitlab/server/lib.ts (1)

1-31: LGTM!

packages/web-ui-registration/src/LoginServicesButton.tsx (1)

30-37: LGTM!

apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx (1)

4-4: Verify TwoFactorModal wiring for emailOrUsername prop
TwoFactorEmailModal now requires emailOrUsername: string (and the resendEmail callback prop is removed). Ensure apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx passes emailOrUsername to TwoFactorEmailModal for the email flow (props.method === Method.EMAIL) so the updated props contract is satisfied.

apps/meteor/app/api/server/ApiClass.ts (1)

147-161: Verify generateConnection has no external consumers
Search for the generateConnection identifier in other TypeScript files returned no matches, so it appears to be internal-only.

apps/meteor/definition/externals/meteor/accounts-base.d.ts (1)

26-26: Confirm accounts-base.d.ts return types match Meteor’s implementation.

  • _insertLoginToken: Meteor awaits it for side effects and the resolved value isn’t used in the documented flow, so void is consistent.
  • updateOrCreateUserFromExternalService: the Meteor docs/source we found describe the hook contract (setAdditionalFindUserOnExternalLogin returns a user or undefined), but don’t specify the exact return type of updateOrCreateUserFromExternalService itself—re-check against the specific Meteor version before assuming the Promise→sync change (and removal of | undefined) is safe.
apps/meteor/app/wordpress/server/lib.ts (1)

1-95: LGTM!

apps/meteor/app/api/server/index.ts (1)

48-50: LGTM!

packages/web-ui-registration/src/LoginServices.tsx (1)

1-40: LGTM!

apps/meteor/app/nextcloud/server/lib.ts (1)

1-38: LGTM!

apps/meteor/client/lib/sdk/ddpSdk.ts (1)

71-71: Confirm readStoredLoginToken has no external consumers (module-local).
A repo-wide search shows readStoredLoginToken is only defined and referenced within apps/meteor/client/lib/sdk/ddpSdk.ts (definition at line 71; internal uses at lines 94 and 131). No other modules import or reference readStoredLoginToken from ddpSdk.ts (other imports from the file are for getDdpSdk / ensureConnectedAndAuthenticated).

apps/meteor/server/configuration/accounts_meld.js (1)

21-24: LGTM!

apps/meteor/app/2fa/server/code/index.ts (4)

66-77: LGTM!


121-139: LGTM!


149-165: LGTM!


167-240: LGTM!

apps/meteor/client/lib/2fa/process2faReturn.ts (4)

31-38: LGTM!


40-84: LGTM!


86-121: LGTM!


123-167: Email 2FA “resend code” remains implemented (no resendEmail prop required)

invokeTwoFactorModal passes emailOrUsername through to TwoFactorModal via ...props, and TwoFactorEmailModal itself renders the “Cloud_resend_email” button and performs the resend by calling POST /v1/users.2fa.sendEmailCode in onClickResendCode (so removing a resendEmail prop from the modal props won’t break resend).

Comment thread apps/meteor/app/apple/lib/handleIdentityToken.ts
Comment thread apps/meteor/app/apple/server/appleOauthRegisterService.ts Outdated
Comment thread apps/meteor/app/apple/server/loginHandler.ts Outdated
@ggazzo ggazzo force-pushed the chore/ddp-migrate-batch2 branch from 4deb36d to 7dbdade Compare May 28, 2026 17:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/ddp-migrate-batch2-callers.md:
- Around line 5-9: Update the change note so it accurately describes that only
the channel-specific joinRoom flow was migrated: clarify that joinRoom for
room.type === 'c' now maps to POST /v1/channels.join and that non-channel
joinRoom paths remain on DDP and are not deprecation-logged; reference the
joinRoom DDP handler and the REST route POST /v1/channels.join in the wording to
make the distinction explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 85b2485b-c201-406d-8bd7-015e3d632c98

📥 Commits

Reviewing files that changed from the base of the PR and between f4c9d38 and 4deb36d.

📒 Files selected for processing (5)
  • .changeset/ddp-migrate-batch2-callers.md
  • .changeset/rest-chat-delete-by-fileid.md
  • .changeset/rest-spotlight-params-and-anonymous.md
  • .changeset/rest-subscriptions-read-tmid.md
  • .changeset/rest-users-setpreferences-utcoffset.md
✅ Files skipped from review due to trivial changes (4)
  • .changeset/rest-users-setpreferences-utcoffset.md
  • .changeset/rest-chat-delete-by-fileid.md
  • .changeset/rest-subscriptions-read-tmid.md
  • .changeset/rest-spotlight-params-and-anonymous.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: 🔎 Code Check / TypeScript
  • GitHub Check: 🔎 Code Check / Code Lint
  • GitHub Check: 🔨 Test Storybook / Test Storybook
  • GitHub Check: 🔨 Test Unit / Unit Tests
  • GitHub Check: 📦 Meteor Build (coverage)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-16T21:50:37.589Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39676
File: .changeset/migrate-users-register-openapi.md:3-3
Timestamp: 2026-03-16T21:50:37.589Z
Learning: For changes related to OpenAPI migrations in Rocket.Chat/OpenAPI, when removing endpoint types and validators from rocket.chat/rest-typings (e.g., UserRegisterParamsPOST, /v1/users.register) document this as a minor changeset (not breaking) per RocketChat/Rocket.Chat-Open-API#150 Rule 7. Note that the endpoint type is re-exposed via a module augmentation .d.ts in the consuming package (e.g., packages/web-ui-registration/src/users-register.d.ts). In reviews, ensure the changeset clearly states: this is a non-breaking change, the major version should not be bumped, and the changeset reflects a minor version bump. Do not treat this as a breaking change during OpenAPI migrations.

Applied to files:

  • .changeset/ddp-migrate-batch2-callers.md

Comment thread .changeset/ddp-migrate-batch2-callers.md Outdated
@coderabbitai coderabbitai Bot added type: feature Pull requests that introduces new feature and removed type: chore labels May 28, 2026
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 8 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/api/server/v1/chat.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/chat.ts:550">
P2: Reject requests that include both `fileId` and `msgId` to avoid ambiguous delete-target resolution.</violation>
</file>

<file name="apps/meteor/app/lib/server/methods/joinRoom.ts">

<violation number="1" location="apps/meteor/app/lib/server/methods/joinRoom.ts:19">
P2: Unconditional deprecation log contradicts PR intent — `joinRoom` is still called via DDP for non-channel types (private groups, DMs, livechat) where `channels.join` does not apply. This will produce noisy deprecation warnings for legitimate DDP usage that has no REST equivalent yet. Consider either removing the log or making it conditional on room.t === 'c' after the room is fetched.</violation>
</file>

<file name="packages/rest-typings/src/v1/chat.ts">

<violation number="1" location="packages/rest-typings/src/v1/chat.ts:249">
P2: Use `oneOf` (or make the branches mutually exclusive) so mixed `fileId` + `msgId`/`roomId` payloads are rejected instead of silently taking the file-id branch.

(Based on your team's feedback about keeping API typings aligned with runtime endpoints.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx">

<violation number="1" location="apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx:74">
P3: Add `.catch(() => undefined)` to suppress potential unhandled promise rejections—this matches the pattern already used for the same `markThreadRead` call in `useThreadMessagesQuery.ts`.</violation>
</file>

<file name="packages/rest-typings/src/v1/misc.ts">

<violation number="1" location="packages/rest-typings/src/v1/misc.ts:86">
P3: `typeof [] === 'object'` in JavaScript, so this check would accept an array as a valid `SpotlightType`. Add `Array.isArray(parsed)` guard to reject non-plain-object inputs.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread apps/meteor/client/providers/CustomSoundProvider/CustomSoundProvider.tsx Outdated
ggazzo added 12 commits June 11, 2026 14:12
Dispatches by room type. For `type === 'c'` the channel case hits
the REST endpoint; other types (private groups, DMs, livechat)
keep the DDP `joinRoom` method until /v1/* coverage catches up.
… join

Drop the DDP fallback — non-channel rooms already failed via DDP too;
the REST error path is equivalent. TODO marks the gap until a
type-agnostic REST endpoint exists.
userSetUtcOffset → /v1/users.setPreferences (utcOffset field added;
  server saves at user-document root via Users.setUtcOffset, not the
  settings.preferences subdoc).

deleteFileMessage → /v1/chat.delete (body now accepts fileId as an
  alternative to msgId+roomId; server resolves the message via
  Messages.getMessageByFileId).

readThreads → /v1/subscriptions.read (body now accepts tmid; server
  routes to readThread(tmid) instead of readMessages).

spotlight → /v1/spotlight (query now accepts usernames CSV, type JSON,
  rid; response type includes nickname/outside/uids/usernames/fname
  that the DDP version already returned).

Each DDP method gets a deprecation log pointing at the REST route.
Server returns outside/external users without a status field (and
DDP callers happily handled the absence). Marking it required broke
the response validation: GET /v1/spotlight 'must have required
property status'.
The hooks/useJoinRoom was already migrated. data.ts (the chat-data API
consumed by message flows) still went through DDP, which throws under
TEST_MODE='true' because of the deprecation log and broke beforeEach
hooks in anonymous-user / embedded-layout specs.
DDP spotlight ran for anonymous DDP sessions (no this.userId), which
was how the anonymous-user e2e specs reached 'general' via the
navbar search. The REST migration kept authRequired: true and broke
those specs (along with embedded-layout) because navbar.openChat
hung on the empty listbox. Set authRequired: false and pass the
optional this.userId through.
The REST endpoint already exists (paginated). Caller in
CustomSoundProvider switches from `sdk.call('listCustomSounds')` to
`useEndpoint('GET', '/v1/custom-sounds.list')`, drops `_updatedAt`
from the spread to satisfy the Omit<…, '_updatedAt'> return type, and
the helper now takes a narrower shape so REST + the local
defaultSounds list type-check the same way.

Server method gets a deprecation log pointing at the REST route.
Five entries: one per touched REST endpoint (chat.delete, users.setPreferences,
subscriptions.read, spotlight) plus a single summary for the client caller
swaps that don't change any REST shape.
- CustomSoundProvider: page through /v1/custom-sounds.list until total
  reached so all sounds load (legacy listCustomSounds returned all at once)
- threads: extract readThreadMethod replicating legacy readThreads behavior
  (Threads_enabled, room access, beforeReadMessages callback); use it in both
  the DDP method and the subscriptions.read tmid branch
- chat.delete: support deleting an uploaded file with no associated message
  via the Uploads store; make _id/ts/message optional in the response
- useLoadMissedMessages: only upsert genuinely-new or already-loaded synced
  messages and remove deleted ones, avoiding stale-history pollution from the
  _updatedAt-based chat.syncMessages
- add API tests for subscriptions.read (tmid), chat.delete (fileId), spotlight
  (type/usernames/anonymous) and users.setPreferences (utcOffset)
@ggazzo ggazzo force-pushed the chore/ddp-migrate-batch2 branch from 2379bca to 46a920e Compare June 11, 2026 17:16

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/api/server/v1/chat.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/chat.ts:550">
P2: Reject requests that include both `fileId` and `msgId` to avoid ambiguous delete-target resolution.</violation>
</file>

<file name="apps/meteor/app/lib/server/methods/joinRoom.ts">

<violation number="1" location="apps/meteor/app/lib/server/methods/joinRoom.ts:19">
P2: Unconditional deprecation log contradicts PR intent — `joinRoom` is still called via DDP for non-channel types (private groups, DMs, livechat) where `channels.join` does not apply. This will produce noisy deprecation warnings for legitimate DDP usage that has no REST equivalent yet. Consider either removing the log or making it conditional on room.t === 'c' after the room is fetched.</violation>
</file>

<file name="packages/rest-typings/src/v1/chat.ts">

<violation number="1" location="packages/rest-typings/src/v1/chat.ts:249">
P2: Use `oneOf` (or make the branches mutually exclusive) so mixed `fileId` + `msgId`/`roomId` payloads are rejected instead of silently taking the file-id branch.

(Based on your team's feedback about keeping API typings aligned with runtime endpoints.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx">

<violation number="1" location="apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx:74">
P3: Add `.catch(() => undefined)` to suppress potential unhandled promise rejections—this matches the pattern already used for the same `markThreadRead` call in `useThreadMessagesQuery.ts`.</violation>
</file>

<file name="packages/rest-typings/src/v1/misc.ts">

<violation number="1" location="packages/rest-typings/src/v1/misc.ts:86">
P3: `typeof [] === 'object'` in JavaScript, so this check would accept an array as a valid `SpotlightType`. Add `Array.isArray(parsed)` guard to reject non-plain-object inputs.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread apps/meteor/app/api/server/v1/chat.ts
@ggazzo ggazzo force-pushed the chore/ddp-migrate-batch2 branch from 8725fba to 797dae4 Compare June 12, 2026 01:45
- chat.delete: revert error string from 'id:' back to 'id of' (regression)
- chat.delete test: orphan file (no associated message) returns 400, not 200
- spotlight test: query a prefix so the usernames exclusion path runs
  (exact-username matches bypass the exclusion list)
- subscriptions.read test: tunread is left as an empty array, not unset
sampaiodiego
sampaiodiego previously approved these changes Jun 12, 2026
The thread read-marker migration (subscriptions.read tmid endpoint +
ThreadChat/useThreadMessagesQuery callers) moves to its own PR #40957.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 9 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx">

<violation number="1">
P1: Custom agent: **Detect usage of deprecated HTTP endpoints or API helpers**

Use of deprecated DDP method `readThreads` instead of the migrated REST endpoint `POST /v1/subscriptions.read`</violation>
</file>

<file name="apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMessagesQuery.ts">

<violation number="1">
P1: Custom agent: **Detect usage of deprecated HTTP endpoints or API helpers**

Introduces deprecated DDP method 'readThreads' while a REST alternative was already in use, contradicting the PR's DDP→REST migration goal</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

@ggazzo ggazzo merged commit 9a36221 into develop Jun 15, 2026
48 checks passed
@ggazzo ggazzo deleted the chore/ddp-migrate-batch2 branch June 15, 2026 20:35
ggazzo added a commit that referenced this pull request Jun 17, 2026
Reverts the loadMissedMessages deprecation added in #40711. Removes the
new chat.history REST endpoint (types, tests) and points the reconnect
catch-up back at the loadMissedMessages DDP method.

chat.syncMessages would be the right long-term target (it also reconciles
edits/deletions on reconnect), but its _updatedAt + trash-collection query
is currently too slow for this path; left a TODO to optimize that query
before migrating.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants